iT邦幫忙

2023 iThome 鐵人賽

DAY 19
0
自我挑戰組

JS 加強筆記系列 第 19

Day 19:promisification (1)

  • 分享至 

  • xImage
  •  

promisification 是指將 callback-based 函式轉換成回傳 promise 的函式。先前文中曾嘗試把 loadScript 改成使用 promise,而在實務上如果有大量函式需要轉換,可以利用一個 helper function 來統一轉換工作。

以單一一個 callback 函式而言,一種簡單的轉換方式是不改變它的使用、直接在外面包一層函式回傳 promise,就像下方的 loadScriptPromiseloadScriptPromise 本身不傳入 callback,而是在裡面執行原本的 loadScript 時,提供 callback 參數給它,讓它可以傳出 promise 結果。這樣一來就可以用原本的方式使用 loadScriptPromise(src) 載入檔案,然後函式也能相容在 promise-based 程式碼中。

// callback based
function loadScript(src, callback) {
    let script = document.createElement('script');
    script.src = src;

    script.onload = () => callback(null, script);
    script.onerror = () => callback(new Error(`Script load error`));

    document.head.append(script);
}

// promisified
function loadScriptPromise(src) {
    return new Promise((resolve, reject) => {
        loadScript(src, (err, script) => {
            if (err) {
                reject(err);
            } else {
                resolve(script);
            }
        });
    });
};

promisify

以上面的方式為基礎,可以建立一個 promisify(f) 來進行包裝轉換:

function promisify(f) {
    return function (...args) {
        return new Promise((resolve, reject) => {
            function callback(err, result) { // 4
                if (err) {
                    reject(err);
                } else {
                    resolve(result);
                }
            }
            args.push(callback); // 11
            f.call(this, ...args); // 12
        });
    };
}

// 使用
let loadScriptPromise = promisify(loadScript);
loadScriptPromise(...).then(...);

promisify 參數傳入一個要轉換的 callback 函式 f,然後會回傳一個 wrapper function,裡面做的就是如同前個例子中 loadScriptPromise 做的事:

  • 回傳 promise
  • 建立要提供給 f 的 callback,讓它可以 resolve/ reject (4)
  • 把 callback 加進參數中 (11)
  • 以這些參數呼叫 f (12)

利用 promisify 就可以不用逐一改寫原有的 callback 函式。


上一篇
Day 18:Promise.all 與 Promise.allSettled 實例
下一篇
Day 19:promisification (2)
系列文
JS 加強筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言